import {
  isUndefined,
  isNull,
  PagedList,
  PageParams,
  camelCaseToUnderscore,
  underscoreToCamelCase,
  toString,
} from "mmb";
import * as wxpay_applymentpb from "../grpc-client/service/wxpay_applyment_pb";
import { jsTimestampToPb, pbTimestampToJs } from "./helper";

import {
  getBgsWxpayApplymentOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";
import {
  WxpayApplyment,
  WxpayApplyFormData,
  UpsertWxpayApplymentParams,
  UpdateWxpayApplymentApplyNoParams,
  UpdateWxpayApplymentProxyResultParams,
  UpsertWxpayApplymentRet,
} from "./declareTypes";
import { getPub, makeTopicOfPub, wrapToMessage } from "../proxy/nsqProxy";
import ProxyApplyStatus from "../bg-enums/proxyApplyStatus";
import GrpcErrCode from "../grpc-client/grpcErrCode";
import { getMchIdAsServiceVar } from "../store/vars";

/****************************************************************************************/
/*                                   wxpay_applyment entity                                */
/****************************************************************************************/
const topicOfUpsertWxpayApplyment = "upsert-wxpay_applyment";

const WxpayApplymentPbToObject = (
  pb: wxpay_applymentpb.WxpayApplymentEntity
): WxpayApplyment => {
  return {
    wxpayApplymentId: `${pb.getId()}`,
    brandId: `${pb.getBrandId()}`,
    wxpayMchIdAsService: pb.getWxpayMchIdAsService(),
    proxyApplyStatus: pb.getProxyApplyStatus() as ProxyApplyStatus,
    applyFormData: underscoreToCamelCase(JSON.parse(pb.getApplyFormData())),
    applyNo: pb.getApplyNo(),
    wxApplymentId: pb.getWxApplymentId(),
    applyState: pb.getApplyState(),
    applyStateDesc: pb.getApplyStateDesc(),
    signUrl: pb.getSignUrl(),
    accountValidation:
      pb.getAccountValidation() === ""
        ? undefined
        : JSON.parse(pb.getAccountValidation()),
    wxpayMchIdAsSub: pb.getWxpayMchIdAsSub(),
    auditDetails:
      pb.getAuditDetails() === ""
        ? undefined
        : JSON.parse(pb.getAuditDetails()),
    legalValidationUrl: pb.getLegalValidationUrl(),
  };
};

/****************************************************************************************/
/*                                   wxpay_applyment cmd                                */
/****************************************************************************************/

export const upsertWxpayApplyment = async ({
  brandId,
  applyFormData,
}: UpsertWxpayApplymentParams): Promise<UpsertWxpayApplymentRet> => {
  const cl = getBgsWxpayApplymentOpSafely();
  const req = new wxpay_applymentpb.UpsertWxpayApplymentRequest();
  req.setBrandId(Number(brandId));
  const wxpayMchIdAsService = getMchIdAsServiceVar();
  req.setWxpayMchIdAsService(wxpayMchIdAsService);
  if (isUndefined(applyFormData.mchId)) {
    applyFormData.mchId = wxpayMchIdAsService;
  }
  req.setApplyFormData(JSON.stringify(camelCaseToUnderscore(applyFormData)));

  return new Promise((resolve, reject) => {
    cl.upsertWxpayApplyment(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve({
          wxpayApplyment: WxpayApplymentPbToObject(res.getWxpayApplyment()!),
          sgId: toString(res.getSgId()),
        });
      }
    );
  });
};

export const updateWxpayApplymentApplyNo = async ({
  wxpayApplymentId,
  applyNo,
}: UpdateWxpayApplymentApplyNoParams): Promise<WxpayApplyment> => {
  const cl = getBgsWxpayApplymentOpSafely();
  const req = new wxpay_applymentpb.UpdateWxpayApplymentApplyNoRequest();

  req.setId(Number(wxpayApplymentId));
  req.setApplyNo(applyNo);

  return new Promise((resolve, reject) => {
    cl.updateWxpayApplymentApplyNo(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(WxpayApplymentPbToObject(res.getWxpayApplyment()!));
      }
    );
  });
};

export const updateWxpayApplymentProxyResult = async ({
  wxpayApplymentId,
  wxApplymentId,
  applyState,
  applyStateDesc,
  signUrl,
  accountValidation,
  wxpayMchIdAsSub,
  auditDetails,
  legalValidationUrl,
  applyFormData,
}: UpdateWxpayApplymentProxyResultParams): Promise<WxpayApplyment> => {
  const cl = getBgsWxpayApplymentOpSafely();
  const req = new wxpay_applymentpb.UpdateWxpayApplymentProxyResultRequest();

  req.setId(Number(wxpayApplymentId));
  if (!isUndefined(wxApplymentId)) {
    req.setWxApplymentId(wxApplymentId);
  }
  if (!isUndefined(applyState)) {
    req.setApplyState(applyState);
  }
  if (!isUndefined(applyStateDesc)) {
    req.setApplyStateDesc(applyStateDesc);
  }
  if (!isUndefined(signUrl)) {
    req.setSignUrl(signUrl);
  }
  if (!isUndefined(accountValidation)) {
    req.setAccountValidation(JSON.stringify(accountValidation));
  }
  if (!isUndefined(wxpayMchIdAsSub)) {
    req.setWxpayMchIdAsSub(wxpayMchIdAsSub);
  }
  if (!isUndefined(auditDetails)) {
    req.setAuditDetails(JSON.stringify(auditDetails));
  }
  if (!isUndefined(legalValidationUrl)) {
    req.setLegalValidationUrl(legalValidationUrl);
  }
  req.setApplyFormData(JSON.stringify(camelCaseToUnderscore(applyFormData)));

  return new Promise((resolve, reject) => {
    cl.updateWxpayApplymentProxyResult(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(WxpayApplymentPbToObject(res.getWxpayApplyment()!));
      }
    );
  });
};

export const checkWxpayApplyFormData = ({
  applyType, // ecommerce/apply4sub
  // 商户号
  mchId,
  // 主体类型
  organizationType, // 2401~小微商户,2~企业 4~个体工商户
  // 营业执照/登记证书信息
  bizLicenseInfo,
  // 组织机构代码证信息
  organizationCertInfo,
  // 经营者/法人证件类型
  idDocType,
  // 经营者/法人身份证信息
  idCardInfo,
  // 经营者/法人其他类型证件信息
  idDocInfo,
  // 是否填写结算银行账户
  needAccountInfo,
  // 结算银行账户
  accountInfo,
  // 超级管理员信息
  contactInfo,
  // 店铺信息
  salesSceneInfo,
  // 商户简称
  merchantShortname,
  // 特殊资质
  qualifications,
  // 补充材料
  businessAdditionPics,
  // 补充说明
  businessAdditionDesc,
}: WxpayApplyFormData) => {
  if (applyType != "ecommerce") {
    throw Error(`applyType not supoort`);
  }

  if (!["2401", "4", "2"].includes(organizationType)) {
    throw Error("organizationType not support");
  }

  if (["4", "2"].includes(organizationType)) {
    // 企业/个体工商户
    if (isUndefined(bizLicenseInfo)) {
      throw Error("bizLicenseInfo need");
    }

    if (isUndefined(bizLicenseInfo.businessLicenseCopy)) {
      throw Error("bizLicenseInfo.businessLicenseCopy need");
    }
    if (isUndefined(bizLicenseInfo.businessLicenseNumber)) {
      throw Error("bizLicenseInfo.businessLicenseNumber need");
    }
    if (isUndefined(bizLicenseInfo.merchantName)) {
      throw Error("bizLicenseInfo.merchantName need");
    }
    if (isUndefined(bizLicenseInfo.legalPerson)) {
      throw Error("bizLicenseInfo.legalPerson need");
    }
  }

  if (idDocType !== "IDENTIFICATION_TYPE_MAINLAND_IDCARD") {
    throw Error("idDocType invalid");
  }
  if (isUndefined(idCardInfo)) {
    throw Error("idCardInfo need");
  }
  if (isUndefined(idCardInfo.idCardCopy)) {
    throw Error("idCardInfo.idCardCopy need");
  }
  if (isUndefined(idCardInfo.idCardNational)) {
    throw Error("idCardInfo.idCardNational need");
  }
  if (isUndefined(idCardInfo.idCardName)) {
    throw Error("idCardInfo.idCardName need");
  }
  if (isUndefined(idCardInfo.idCardNumber)) {
    throw Error("idCardInfo.idCardNumber need");
  }

  if (needAccountInfo) {
    if (isUndefined(accountInfo)) {
      throw Error("accountInfo need");
    }
    if (isUndefined(accountInfo.bankAccountType)) {
      throw Error("accountInfo.bankAccountType need");
    }
    if (organizationType === "2401" && accountInfo.bankAccountType !== "75") {
      throw Error("2401 accountInfo.bankAccountType invalid");
    }
    if (organizationType === "2" && accountInfo.bankAccountType !== "74") {
      throw Error("2 accountInfo.bankAccountType invalid");
    }
    if (
      organizationType === "4" &&
      !["74", "75"].includes(accountInfo.bankAccountType)
    ) {
      throw Error("4 accountInfo.bankAccountType invalid");
    }

    if (isUndefined(accountInfo.accountBank)) {
      throw Error("accountInfo.accountBank need");
    }
    if (isUndefined(accountInfo.accountName)) {
      throw Error("accountInfo.accountName need");
    }
    if (isUndefined(accountInfo.bankAddressCode)) {
      throw Error("accountInfo.bankAddressCode need");
    }
    if (isUndefined(accountInfo.accountNumber)) {
      throw Error("accountInfo.accountNumber need");
    }
  }

  if (isUndefined(contactInfo)) {
    throw Error("contactInfo need");
  }
  if (isUndefined(contactInfo.contactType)) {
    throw Error("contactInfo.contactType need");
  }
  if (organizationType === "2401" && contactInfo.contactType !== "65") {
    throw Error("2401 accountInfo.bankAccountType invalid");
  }
  if (
    ["2", "4"].includes(organizationType) &&
    !["65", "66"].includes(contactInfo.contactType)
  ) {
    throw Error("4 accountInfo.bankAccountType invalid");
  }

  if (isUndefined(contactInfo.contactName)) {
    throw Error("contactInfo.contactName need");
  }
  if (isUndefined(contactInfo.contactIdCardNumber)) {
    throw Error("contactInfo.contactIdCardNumber need");
  }
  if (isUndefined(contactInfo.mobilePhone)) {
    throw Error("contactInfo.mobilePhone need");
  }

  if (isUndefined(salesSceneInfo)) {
    throw Error("salesSceneInfo need");
  }
  if (isUndefined(salesSceneInfo.storeName)) {
    throw Error("salesSceneInfo.storeName need");
  }
  if (
    isUndefined(salesSceneInfo.storeUrl) &&
    isUndefined(salesSceneInfo.storeQrCode)
  ) {
    throw Error("salesSceneInfo.storeUrl or storeQrCode need");
  }

  if (isUndefined(merchantShortname)) {
    throw Error("merchantShortname need");
  }

  console.log("kWxpayApplyFormData valid success!");
};

/****************************************************************************************/
/*                                   wxpay_applyment query                              */
/****************************************************************************************/

export const getWxpayApplyment = async (
  WxpayApplymentId: string
): Promise<WxpayApplyment> => {
  const cl = getBgsWxpayApplymentOpSafely();
  const req = new wxpay_applymentpb.GetWxpayApplymentRequest();

  req.setId(Number(WxpayApplymentId));

  return new Promise((resolve, reject) => {
    cl.getWxpayApplyment(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(WxpayApplymentPbToObject(res.getWxpayApplyment()!));
      }
    );
  });
};

export const getWxpayApplymentByBrandID = async (
  brandId: string
): Promise<WxpayApplyment | undefined> => {
  const cl = getBgsWxpayApplymentOpSafely();
  const req = new wxpay_applymentpb.GetWxpayApplymentByBrandIDRequest();

  req.setBrandId(Number(brandId));

  return new Promise((resolve, reject) => {
    cl.getWxpayApplymentByBrandID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          if (opRet.getCode() === GrpcErrCode.NOT_FOUND) {
            resolve(undefined);
            return;
          } else {
            reject(wrapperGrpcError(opRet.getMsg()));
            return;
          }
        }
        resolve(WxpayApplymentPbToObject(res.getWxpayApplyment()!));
      }
    );
  });
};

export const getWxpayApplymentAndRemindWxpay = async (
  brandId: string
): Promise<WxpayApplyment | undefined> => {
  const cl = getBgsWxpayApplymentOpSafely();
  const req = new wxpay_applymentpb.GetWxpayApplymentAndRemindWxpayRequest();

  req.setBrandId(Number(brandId));

  return new Promise((resolve, reject) => {
    cl.getWxpayApplymentAndRemindWxpay(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          if (opRet.getCode() === GrpcErrCode.NOT_FOUND) {
            resolve(undefined);
            return;
          } else {
            reject(wrapperGrpcError(opRet.getMsg()));
            return;
          }
        }
        resolve(WxpayApplymentPbToObject(res.getWxpayApplyment()!));
      }
    );
  });
};
